home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / Maze / MazeCommon / MazeServer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  41.1 KB  |  1,320 lines

  1. //----------------------------------------------------------------------------
  2. // File: mazeserver.cpp
  3. //
  4. // Desc: see main.cpp
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #define D3D_OVERLOADS
  10. #include <windows.h>
  11. #include <d3dx.h>
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <mmsystem.h>
  15. #include <dplay8.h>
  16. #include <dpaddr.h>
  17. #include <dxerr8.h>
  18. #include "DXUtil.h"
  19. #include "MazeServer.h"
  20. #include "Packets.h"
  21. #include "Maze.h"
  22. #include <malloc.h>
  23. #include <tchar.h>
  24.  
  25.  
  26.  
  27. //-----------------------------------------------------------------------------
  28. // Name: 
  29. // Desc: 
  30. //-----------------------------------------------------------------------------
  31. CMazeServer::CMazeServer()
  32. {
  33.     m_dwPlayerCount         = 0;
  34.     
  35.     m_wActiveThreadCount   = 0;
  36.     m_wMaxThreadCount      = 0;
  37.     m_fAvgThreadCount      = 0;
  38.     m_fAvgThreadTime       = 0;
  39.     m_fMaxThreadTime       = 0;
  40.  
  41.     m_dwServerReliableRate  = 15;
  42.     m_dwServerTimeout       = 150;
  43.     m_dwLogLevel            = 2;
  44.     m_pMaze                 = NULL;
  45.  
  46.     m_ClientNetConfig.ubReliableRate = 15;
  47.     m_ClientNetConfig.wUpdateRate    = 150;
  48.     m_ClientNetConfig.wTimeout       = 150;
  49.  
  50.     m_ClientNetConfig.dwThreadWait = 0;
  51.  
  52.     m_ClientNetConfig.ubClientPackIndex = 0;
  53.     m_ClientNetConfig.ubServerPackIndex = 0;
  54.     for(WORD x = 0; x < PACK_ARRAY_SIZE; x++)
  55.     {
  56.         m_ClientNetConfig.wClientPackSizeArray[x] = 0;
  57.         m_ClientNetConfig.wServerPackSizeArray[x] = 0;
  58.     }
  59. }
  60.  
  61.  
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Name: 
  66. // Desc: 
  67. //-----------------------------------------------------------------------------
  68. HRESULT CMazeServer::Init( BOOL bLocalLoopback, const CMaze* pMaze )
  69. {
  70.     m_bLocalLoopback = bLocalLoopback;
  71.     m_pMaze = pMaze;
  72.     if( m_pMaze == NULL )
  73.         return DXTRACE_ERR( TEXT("Param"), E_FAIL );
  74.  
  75.     // Grab height and width of maze
  76.     m_dwWidth = m_pMaze->GetWidth();
  77.     m_dwHeight = m_pMaze->GetHeight();
  78.  
  79.     m_ClientNetConfig.dwMazeWidth  = m_dwWidth;
  80.     m_ClientNetConfig.dwMazeHeight = m_dwHeight;
  81.  
  82.     // Validate size. Must be a power-of-2 times LOCK_GRID_SIZE. Compute the shifts.
  83.     if( m_dwWidth > SERVER_MAX_WIDTH || m_dwHeight > SERVER_MAX_HEIGHT )
  84.         return DXTRACE_ERR( TEXT("Maze height and width need to be less than 128"), E_INVALIDARG );
  85.     if( (m_dwWidth % LOCK_GRID_SIZE) != 0 || (m_dwHeight % LOCK_GRID_SIZE) != 0 )
  86.         return DXTRACE_ERR( TEXT("Maze height and width need to be divisable by 16"), E_INVALIDARG );
  87.  
  88.     DWORD scale = m_dwWidth / LOCK_GRID_SIZE;
  89.     m_dwMazeXShift = 0;
  90.     while ( (scale >>= 1) )
  91.         m_dwMazeXShift++;
  92.  
  93.     scale = m_dwHeight / LOCK_GRID_SIZE;
  94.     m_dwMazeYShift = 0;
  95.     while ( (scale >>= 1) )
  96.         m_dwMazeYShift++;
  97.  
  98.     if( ((DWORD(LOCK_GRID_SIZE) << m_dwMazeXShift) != m_dwWidth) ||
  99.         ((DWORD(LOCK_GRID_SIZE) << m_dwMazeYShift) != m_dwHeight) )
  100.         return DXTRACE_ERR( TEXT("Maze height and width need to be power of 2"), E_INVALIDARG );
  101.  
  102.     // Initialise the player list
  103.     ZeroMemory( m_PlayerDatas, sizeof(m_PlayerDatas) );
  104.     m_pFirstActivePlayerData = NULL;
  105.     m_pFirstFreePlayerData = m_PlayerDatas;
  106.     for( DWORD i = 1; i < MAX_PLAYER_OBJECTS-1; i++ )
  107.     {
  108.         m_PlayerDatas[i].pNext = &m_PlayerDatas[i+1];
  109.         m_PlayerDatas[i].pPrevious = &m_PlayerDatas[i-1];
  110.     }
  111.  
  112.     m_PlayerDatas[0].pNext = &m_PlayerDatas[1];
  113.     m_PlayerDatas[MAX_PLAYER_OBJECTS-1].pPrevious = &m_PlayerDatas[MAX_PLAYER_OBJECTS-2];
  114.     m_dwActivePlayerDataCount = 0;
  115.     m_dwPlayerDataUniqueValue = 0;
  116.  
  117.     // Initialise the cells
  118.     ZeroMemory( m_Cells, sizeof(m_Cells) );
  119.     ZeroMemory( &m_OffMapCell, sizeof(m_OffMapCell) );
  120.  
  121.     return S_OK;
  122. }
  123.  
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // Name: 
  129. // Desc: 
  130. //-----------------------------------------------------------------------------
  131. void CMazeServer::Shutdown()
  132. {
  133. }
  134.  
  135.  
  136.  
  137.  
  138. //-----------------------------------------------------------------------------
  139. // Name: 
  140. // Desc: 
  141. //-----------------------------------------------------------------------------
  142. void CMazeServer::LockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
  143. {
  144.     m_LockGrid.LockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,
  145.                           x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
  146. }
  147.  
  148.  
  149.  
  150.  
  151. //-----------------------------------------------------------------------------
  152. // Name: 
  153. // Desc: 
  154. //-----------------------------------------------------------------------------
  155. void CMazeServer::UnlockRange( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
  156. {
  157.     m_LockGrid.UnlockRange( x1>>m_dwMazeXShift, y1>>m_dwMazeYShift ,
  158.                             x2>>m_dwMazeXShift, y2>>m_dwMazeYShift );
  159. }
  160.  
  161.  
  162.  
  163.  
  164. //-----------------------------------------------------------------------------
  165. // Name: 
  166. // Desc: 
  167. //-----------------------------------------------------------------------------
  168. void CMazeServer::LockCell( DWORD x, DWORD y )
  169. {
  170.     if( x == 0xffff )
  171.         m_OffMapLock.Enter();
  172.     else
  173.         m_LockGrid.LockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);
  174. }
  175.  
  176.  
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // Name: 
  181. // Desc: 
  182. //-----------------------------------------------------------------------------
  183. void CMazeServer::UnlockCell( DWORD x, DWORD y )
  184. {
  185.     if( x == 0xffff )
  186.         m_OffMapLock.Leave();
  187.     else
  188.         m_LockGrid.UnlockCell(x>>m_dwMazeXShift,y>>m_dwMazeYShift);
  189. }
  190.  
  191.  
  192.  
  193.  
  194. //-----------------------------------------------------------------------------
  195. // Name: 
  196. // Desc: 
  197. //-----------------------------------------------------------------------------
  198. void CMazeServer::LockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
  199. {
  200.     if( x1 == x2 && y1 == y2 )
  201.     {
  202.         if( x1 != 0xffff && y2 != 0xffff )
  203.             LockCell( x1, y1 );
  204.         else
  205.             m_OffMapLock.Enter();
  206.  
  207.         return;
  208.     }
  209.  
  210.     DWORD x1shift = x1>>m_dwMazeXShift;
  211.     DWORD x2shift = x2>>m_dwMazeXShift;
  212.     DWORD y1shift = y1>>m_dwMazeYShift;
  213.     DWORD y2shift = y2>>m_dwMazeYShift;
  214.  
  215.     if( x1 == 0xffff )
  216.     {
  217.         m_OffMapLock.Enter();
  218.         m_LockGrid.LockCell(x2shift,y2shift);
  219.     }
  220.     else if( x2 == 0xffff )
  221.     {
  222.         m_OffMapLock.Enter();
  223.         m_LockGrid.LockCell(x1shift,y1shift);
  224.     }
  225.     else 
  226.     {
  227.         m_LockGrid.LockCellPair(x1shift,y1shift,x2shift,y2shift);
  228.     }
  229. }
  230.  
  231.  
  232.  
  233.  
  234. //-----------------------------------------------------------------------------
  235. // Name: 
  236. // Desc: 
  237. //-----------------------------------------------------------------------------
  238. void CMazeServer::UnlockCellPair( DWORD x1, DWORD y1, DWORD x2, DWORD y2 )
  239. {
  240.     if( x1 == x2 && y1 == y2 )
  241.     {
  242.         if( x1 != 0xffff && y2 != 0xffff )
  243.             UnlockCell( x1, y1 );
  244.         else
  245.             m_OffMapLock.Leave();
  246.  
  247.         return;
  248.     }
  249.  
  250.     DWORD x1shift = x1>>m_dwMazeXShift;
  251.     DWORD x2shift = x2>>m_dwMazeXShift;
  252.     DWORD y1shift = y1>>m_dwMazeYShift;
  253.     DWORD y2shift = y2>>m_dwMazeYShift;
  254.  
  255.     if( x1 == 0xffff )
  256.     {
  257.         m_LockGrid.UnlockCell(x2shift,y2shift);
  258.         m_OffMapLock.Leave();
  259.     }
  260.     else if( x2 == 0xffff )
  261.     {
  262.         m_LockGrid.UnlockCell(x1shift,y1shift);
  263.         m_OffMapLock.Leave();
  264.     }
  265.     else 
  266.     {
  267.         m_LockGrid.UnlockCellPair(x1shift,y1shift,x2shift,y2shift);
  268.     }
  269. }
  270.  
  271.  
  272.  
  273.  
  274. //-----------------------------------------------------------------------------
  275. // Name: 
  276. // Desc: 
  277. //-----------------------------------------------------------------------------
  278. void CMazeServer::OnAddConnection( DWORD id )
  279. {
  280.     m_AddRemoveLock.Enter();
  281.  
  282.     // Increment our count of players
  283.     m_dwPlayerCount++;
  284.     if( m_dwLogLevel > 0 )
  285.     {
  286.         ConsolePrintf( SLINE_LOG, TEXT("Adding player DPNID %0.8x"), id );
  287.         ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
  288.     }
  289.  
  290.     if( m_dwPlayerCount > m_dwPeakPlayerCount )
  291.         m_dwPeakPlayerCount = m_dwPlayerCount;
  292.  
  293.     // Create a player for this client
  294.     PlayerData* pPlayerData = CreatePlayerData();
  295.     if( pPlayerData == NULL )
  296.     {
  297.         ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unable to create new PlayerData for client!") );
  298.         DXTRACE_ERR( TEXT("CreatePlayerData"), E_FAIL );
  299.         m_AddRemoveLock.Leave();
  300.         return;
  301.     }
  302.  
  303.     // Store that pointer as local player data
  304.     SetPlayerDataForID( id, pPlayerData );
  305.  
  306.     // Grab net config into to send to client
  307.     m_ClientNetConfigLock.Enter();
  308.     ServerConfigPacket packet( m_ClientNetConfig );
  309.     m_ClientNetConfigLock.Leave();
  310.  
  311.     // Send it
  312.     SendPacket( id, &packet, sizeof(packet), TRUE, 0 );
  313.  
  314.     m_AddRemoveLock.Leave();
  315. }
  316.  
  317.  
  318.  
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Name: 
  322. // Desc: 
  323. //-----------------------------------------------------------------------------
  324. void CMazeServer::OnRemoveConnection( DWORD id )
  325. {
  326.     m_AddRemoveLock.Enter();
  327.  
  328.     // Decrement count of players
  329.     m_dwPlayerCount--;
  330.  
  331.     if( m_dwLogLevel > 0 )
  332.     {
  333.         ConsolePrintf( SLINE_LOG, TEXT("Removing player DPNID %0.8x"), id );
  334.         ConsolePrintf( SLINE_LOG, TEXT("Players connected = %d"), m_dwPlayerCount );
  335.     }
  336.  
  337.     // Find playerdata for this client
  338.     PlayerData* pPlayerData = GetPlayerDataForID( id );
  339.     if( pPlayerData != NULL )
  340.     {
  341.         // Destroy it
  342.         RemovePlayerDataID( pPlayerData );
  343.         DestroyPlayerData( pPlayerData );
  344.     }
  345.  
  346.     m_AddRemoveLock.Leave();
  347. }
  348.  
  349.  
  350.  
  351.  
  352. //-----------------------------------------------------------------------------
  353. // Name: 
  354. // Desc: 
  355. //-----------------------------------------------------------------------------
  356. HRESULT CMazeServer::OnPacket( DWORD dwFrom, void* pData, DWORD size )
  357. {
  358.     BOOL fFoundSize = FALSE;
  359.  
  360.     // Increment the number of thread we have in this process.
  361.     m_csThreadCountLock.Enter();
  362.  
  363.     //Get the start time of when we entered the message handler.
  364.     FLOAT   fStartTime = DXUtil_Timer( TIMER_GETAPPTIME );
  365.  
  366.     m_wActiveThreadCount++;
  367.     if(m_wActiveThreadCount > m_wMaxThreadCount)
  368.         m_wMaxThreadCount = m_wActiveThreadCount;
  369.     
  370.     // Calculate and average.
  371.     FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount;
  372.     m_fAvgThreadCount += fdiff/32;
  373.     
  374.     m_csThreadCountLock.Leave();
  375.  
  376.  
  377.     ClientPacket* pClientPack = (ClientPacket*)pData;
  378.     switch( pClientPack->wType )
  379.     {
  380.         case PACKETTYPE_CLIENT_POS:
  381.             
  382.             // Check to see if the packet has a valid size. Including 
  383.             // the custom pack size.
  384.             if( size < sizeof(ClientPosPacket))
  385.                 fFoundSize = FALSE;
  386.             else if( ! IsValidPackSize(size - sizeof(ClientPosPacket)))
  387.                 fFoundSize = FALSE;
  388.             else
  389.                 fFoundSize = TRUE;
  390.  
  391.             // If valid sized packet, handle the position.
  392.             if(fFoundSize)
  393.                 HandleClientPosPacket( dwFrom, (ClientPosPacket*)pClientPack );
  394.             else
  395.                 m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
  396.  
  397.             break;
  398.  
  399.         case PACKETTYPE_CLIENT_VERSION:
  400.             if( size == sizeof(ClientVersionPacket) )
  401.                 HandleClientVersionPacket( dwFrom, (ClientVersionPacket*)pClientPack );
  402.             else
  403.                 m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
  404.             break;
  405.  
  406.         case PACKETTYPE_SERVER_CONFIG:
  407.  
  408.             // Server config packet sent to all users (including server). Just ignore and continue.
  409.  
  410.             break;
  411.         default:
  412.             HandleUnknownPacket( dwFrom, pClientPack, size );
  413.             break;
  414.     }
  415.  
  416.     //If the user wants to hold the thread, Sleep for given amount of time.
  417.     if ( m_dwServerThreadWait > 0 )
  418.     {
  419.         Sleep( m_dwServerThreadWait );
  420.     }
  421.     
  422.     // Retrieve thread data for this process.
  423.     m_csThreadCountLock.Enter();
  424.  
  425.     m_wActiveThreadCount--;
  426.  
  427.     FLOAT fDiffTime = (DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime) - m_fAvgThreadTime;
  428.     m_fAvgThreadTime += fDiffTime/32;
  429.  
  430.     //Get the Max time in the thread.
  431.     if ( fDiffTime > m_fMaxThreadTime )
  432.     {
  433.         m_fMaxThreadTime = fDiffTime;
  434.     }
  435.  
  436.     m_csThreadCountLock.Leave();
  437.  
  438.     return S_OK;
  439. }
  440.  
  441.  
  442.  
  443. //-----------------------------------------------------------------------------
  444. // Name: 
  445. // Desc: 
  446. //-----------------------------------------------------------------------------
  447. BOOL CMazeServer::IsValidPackSize( DWORD dwSize )
  448. {
  449.     BOOL fFoundSize = FALSE;
  450.     BYTE ubPackLocation = m_ClientNetConfig.ubClientPackIndex;
  451.     
  452.     // Check through the array of valid pack sizes.
  453.     if(dwSize != m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])
  454.     {
  455.         for( --ubPackLocation; ubPackLocation != m_ClientNetConfig.ubClientPackIndex; ubPackLocation--)
  456.         {
  457.             if(dwSize == m_ClientNetConfig.wClientPackSizeArray[ubPackLocation])
  458.             {
  459.                 // Found valid size in the array.
  460.                 fFoundSize = TRUE;
  461.                 break;
  462.             }
  463.             if(ubPackLocation >= PACK_ARRAY_SIZE)  ubPackLocation = PACK_ARRAY_SIZE;  //Wrap the array.
  464.         }
  465.     }
  466.     else
  467.     {
  468.         fFoundSize = TRUE;
  469.     }
  470.  
  471.     return fFoundSize;
  472. }
  473.  
  474.  
  475. //-----------------------------------------------------------------------------
  476. // Name: 
  477. // Desc: 
  478. //-----------------------------------------------------------------------------
  479. void CMazeServer::OnSessionLost( DWORD dwReason )
  480. {
  481.     ConsolePrintf( SLINE_LOG, TEXT("ERROR! Session was lost") );
  482. }
  483.  
  484.  
  485.  
  486.  
  487. //-----------------------------------------------------------------------------
  488. // Name: 
  489. // Desc: 
  490. //-----------------------------------------------------------------------------
  491. PlayerData* CMazeServer::CreatePlayerData()
  492. {
  493.     m_PlayerDataListLock.Enter();
  494.  
  495.     // Grab first free player in the list
  496.     PlayerData* pPlayerData = m_pFirstFreePlayerData;
  497.  
  498.     if( pPlayerData )
  499.     {
  500.         LockPlayerData( pPlayerData );
  501.  
  502.         // Got one, so remove it from the free list
  503.         if( pPlayerData->pPrevious )
  504.             pPlayerData->pPrevious->pNext = pPlayerData->pNext;
  505.         if( pPlayerData->pNext )
  506.             pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;
  507.         m_pFirstFreePlayerData = pPlayerData->pNext;
  508.  
  509.         // Add it to the active list
  510.         if( m_pFirstActivePlayerData )
  511.             m_pFirstActivePlayerData->pPrevious = pPlayerData;
  512.         pPlayerData->pNext = m_pFirstActivePlayerData;
  513.         pPlayerData->pPrevious = NULL;
  514.         m_pFirstActivePlayerData = pPlayerData;
  515.  
  516.         // Update count of players
  517.         m_dwActivePlayerDataCount++;
  518.  
  519.         // Generate the ID for this player
  520.         m_dwPlayerDataUniqueValue++;
  521.         pPlayerData->dwID = (DWORD) ((pPlayerData-m_PlayerDatas)|(m_dwPlayerDataUniqueValue<<PLAYER_OBJECT_SLOT_BITS));
  522.  
  523.         pPlayerData->pNextInIDHashBucket = NULL;
  524.         pPlayerData->NetID = 0;
  525.         pPlayerData->dwNumNearbyPlayers = 0;
  526.  
  527.         // Insert into the "off-map" cell
  528.         pPlayerData->fPosX = pPlayerData->fPosY = -1;
  529.         pPlayerData->wCellX = pPlayerData->wCellY = 0xffff;
  530.         m_OffMapLock.Enter();
  531.         pPlayerData->pNextInCell = m_OffMapCell.pFirstPlayerData;
  532.         m_OffMapCell.pFirstPlayerData = pPlayerData;
  533.         m_OffMapLock.Leave();
  534.  
  535.         // Mark as active
  536.         pPlayerData->bActive = TRUE;
  537.  
  538.         UnlockPlayerData( pPlayerData );
  539.     }
  540.  
  541.     m_PlayerDataListLock.Leave();
  542.  
  543.     return pPlayerData;
  544. }
  545.  
  546.  
  547.  
  548.  
  549. //-----------------------------------------------------------------------------
  550. // Name: 
  551. // Desc: 
  552. //-----------------------------------------------------------------------------
  553. void CMazeServer::DestroyPlayerData( PlayerData* pPlayerData )
  554. {
  555.     m_PlayerDataListLock.Enter();
  556.     LockPlayerData( pPlayerData );
  557.  
  558.     // Remove the player from its cell
  559.     RemovePlayerDataFromCell( pPlayerData );
  560.  
  561.     // Mark as inactive
  562.     pPlayerData->bActive = FALSE;
  563.  
  564.     // Remove player from active list
  565.     if( pPlayerData->pPrevious )
  566.         pPlayerData->pPrevious->pNext = pPlayerData->pNext;
  567.     if( pPlayerData->pNext )
  568.         pPlayerData->pNext->pPrevious = pPlayerData->pPrevious;
  569.  
  570.     if( m_pFirstActivePlayerData == pPlayerData )
  571.         m_pFirstActivePlayerData = pPlayerData->pNext;
  572.  
  573.     // Add it to the free list
  574.     if( m_pFirstFreePlayerData )
  575.         m_pFirstFreePlayerData->pPrevious = pPlayerData;
  576.     pPlayerData->pNext = m_pFirstFreePlayerData;
  577.     pPlayerData->pPrevious = NULL;
  578.     m_pFirstFreePlayerData = pPlayerData;
  579.  
  580.     // Update count of players
  581.     m_dwActivePlayerDataCount--;
  582.  
  583.     UnlockPlayerData( pPlayerData );
  584.     m_PlayerDataListLock.Leave();
  585. }
  586.  
  587.  
  588.  
  589.  
  590. //-----------------------------------------------------------------------------
  591. // Name: 
  592. // Desc: 
  593. //-----------------------------------------------------------------------------
  594. void CMazeServer::RemovePlayerDataFromCell( PlayerData* pPlayerData )
  595. {
  596.     // Lock the player
  597.     LockPlayerData( pPlayerData );
  598.  
  599.     // Lock the cell the player is in
  600.     ServerCell* pCell;
  601.     if( pPlayerData->wCellX == 0xffff )
  602.     {
  603.         m_OffMapLock.Enter();
  604.         pCell = &m_OffMapCell;
  605.     }
  606.     else
  607.     {
  608.         LockCell( pPlayerData->wCellX, pPlayerData->wCellY );
  609.         pCell = &m_Cells[pPlayerData->wCellY][pPlayerData->wCellX];
  610.     }
  611.  
  612.     // Remove it from the cell
  613.     PlayerData* pPt = pCell->pFirstPlayerData;
  614.     PlayerData* pPrev = NULL;
  615.     while ( pPt )
  616.     {
  617.         if( pPt == pPlayerData )
  618.         {
  619.             if( pPrev )
  620.                 pPrev->pNextInCell = pPlayerData->pNextInCell;
  621.             else
  622.                 pCell->pFirstPlayerData = pPlayerData->pNextInCell;
  623.  
  624.             pPlayerData->pNextInCell = NULL;
  625.             break;
  626.         }
  627.         pPrev = pPt;
  628.         pPt = pPt->pNextInCell;
  629.     }
  630.  
  631.     // Unlock the cell
  632.     if( pPlayerData->wCellX == 0xffff )
  633.         m_OffMapLock.Leave();
  634.     else
  635.         UnlockCell( pPlayerData->wCellX, pPlayerData->wCellY );
  636.  
  637.     // Unlock the player
  638.     UnlockPlayerData( pPlayerData );
  639. }
  640.  
  641.  
  642.  
  643.  
  644. //-----------------------------------------------------------------------------
  645. // Name: 
  646. // Desc: 
  647. //-----------------------------------------------------------------------------
  648. void CMazeServer::UnsafeRemovePlayerDataFromCell( PlayerData* pPlayerData )
  649. {
  650.     ServerCell* pCell = GetCell( pPlayerData );
  651.     PlayerData* pPt  = pCell->pFirstPlayerData;
  652.     PlayerData* pPrev = NULL;
  653.     while ( pPt )
  654.     {
  655.         if( pPt == pPlayerData )
  656.         {
  657.             if( pPrev )
  658.                 pPrev->pNextInCell = pPlayerData->pNextInCell;
  659.             else
  660.                 pCell->pFirstPlayerData = pPlayerData->pNextInCell;
  661.             pPlayerData->pNextInCell = NULL;
  662.             break;
  663.         }
  664.         pPrev = pPt;
  665.         pPt = pPt->pNextInCell;
  666.     }
  667. }
  668.  
  669.  
  670.  
  671.  
  672. //-----------------------------------------------------------------------------
  673. // Name: 
  674. // Desc: 
  675. //-----------------------------------------------------------------------------
  676. void CMazeServer::UnsafeAddPlayerDataToCell( PlayerData* pPlayerData )
  677. {
  678.     ServerCell* pCell   = GetCell( pPlayerData );
  679.     pPlayerData->pNextInCell = pCell->pFirstPlayerData;
  680.     pCell->pFirstPlayerData = pPlayerData;
  681. }
  682.  
  683.  
  684.  
  685.  
  686. //-----------------------------------------------------------------------------
  687. // Name: 
  688. // Desc: 
  689. //-----------------------------------------------------------------------------
  690. void CMazeServer::HandleClientPosPacket( DWORD dwFrom, ClientPosPacket* pClientPosPack )
  691. {
  692.     // Grab player for this client and lock it
  693.     PlayerData* pFromPlayer = GetPlayerDataForID( dwFrom );
  694.     if( pFromPlayer == NULL )
  695.     {
  696.         if( m_dwLogLevel > 1 )
  697.             ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Could not find data structure for this player"), pFromPlayer->NetID );
  698.         return;
  699.     }
  700.  
  701.     LockPlayerData( pFromPlayer );
  702.  
  703.     if( FALSE == pFromPlayer->bAllow )
  704.     {
  705.         if( m_dwLogLevel > 0 )
  706.             ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Got position packet from bad client.  Rejecting client"), pFromPlayer->NetID );
  707.  
  708.         m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
  709.         UnlockPlayerData( pFromPlayer );
  710.         return;
  711.     }
  712.  
  713.     // Compute the cell the player should be in now
  714.     DWORD newcellx = int(pClientPosPack->fX);
  715.     DWORD newcelly = int(pClientPosPack->fY);
  716.     DWORD oldcellx = pFromPlayer->wCellX;
  717.     DWORD oldcelly = pFromPlayer->wCellY;
  718.  
  719.     // Have we moved cell?
  720.     if( newcellx != oldcellx || newcelly != oldcelly )
  721.     {
  722.         // Yes, so lock the pair of cells in question
  723.         LockCellPair( oldcellx, oldcelly, newcellx, newcelly );
  724.  
  725.         // Remove from old cell and add to new cell
  726.         UnsafeRemovePlayerDataFromCell( pFromPlayer );
  727.         pFromPlayer->wCellX = WORD(newcellx); pFromPlayer->wCellY = WORD(newcelly);
  728.         UnsafeAddPlayerDataToCell( pFromPlayer );
  729.  
  730.         // Unlock cells
  731.         UnlockCellPair( oldcellx, oldcelly, newcellx, newcelly );
  732.     }
  733.  
  734.     // Update player position
  735.     pFromPlayer->fPosX      = pClientPosPack->fX;
  736.     pFromPlayer->fPosY      = pClientPosPack->fY;
  737.     pFromPlayer->aCameraYaw = pClientPosPack->aCameraYaw;
  738.  
  739.     // Allocate space to build the reply packet, and fill in header 
  740.     DWORD dwAllocSize;
  741.     ServerAckPacket* pSvrAckPack = NULL;
  742.  
  743.     // Begin by allocating a buffer sized according to
  744.     // the current number of nearby players + 4.  This will give 
  745.     // a little room for more players to come 'near' without resize
  746.     // the buffer.
  747.     DWORD dwMaxPlayerStatePackets = pFromPlayer->dwNumNearbyPlayers + 4;
  748.  
  749.     dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket);
  750.     pSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );
  751.     if( NULL == pSvrAckPack )
  752.     {
  753.         // Out of mem.  Cleanup and return
  754.         UnlockPlayerData( pFromPlayer );
  755.         return;       
  756.     }
  757.     ZeroMemory( pSvrAckPack, dwAllocSize );
  758.  
  759.     *pSvrAckPack = ServerAckPacket(m_dwPlayerCount);
  760.     pSvrAckPack->wPlayerStatePacketCount = 0;
  761.     PlayerStatePacket* pChunk = (PlayerStatePacket*)(pSvrAckPack+1);
  762.  
  763.     // Compute range of cells we're going to scan for players to send
  764.     DWORD minx = (newcellx > 7) ? (newcellx - 7) : 0;
  765.     DWORD miny = (newcelly > 7) ? (newcelly - 7) : 0;
  766.     DWORD maxx = (newcellx+7 >= m_dwWidth) ? m_dwWidth-1 : newcellx+7;
  767.     DWORD maxy = (newcelly+7 >= m_dwHeight) ? m_dwHeight-1 : newcelly+7;
  768.  
  769.     // Lock that range of cells
  770.     LockRange( minx, miny, maxx, maxy );
  771.  
  772.     // Scan through the cells, tagging player data onto the end of
  773.     // our pSvrAckPacket until we run out of room
  774.     for( DWORD y = miny; y <= maxy; y++ )
  775.     {
  776.         for( DWORD x = minx; x <= maxx; x++ )
  777.         {
  778.             PlayerData* pCurPlayerData = m_Cells[y][x].pFirstPlayerData;
  779.             while ( pCurPlayerData )
  780.             {
  781.                 if( pCurPlayerData != pFromPlayer )
  782.                 {
  783.                     if( pSvrAckPack->wPlayerStatePacketCount >= dwMaxPlayerStatePackets )
  784.                     {
  785.                         // Make sure pChunk is where we think it is
  786.                         assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );
  787.  
  788.                         // There are more than just 4 new nearby players, so resize the 
  789.                         // buffer pSvrAckPack to allow 16 more PlayerStatePacket's.
  790.                         dwMaxPlayerStatePackets += 16;
  791.                         dwAllocSize = sizeof(ServerAckPacket) + dwMaxPlayerStatePackets*sizeof(PlayerStatePacket);
  792.                         ServerAckPacket* pNewSvrAckPack = NULL;
  793.                         pNewSvrAckPack = (ServerAckPacket*) realloc( pSvrAckPack, dwAllocSize );
  794.                         if( NULL == pNewSvrAckPack )
  795.                         {
  796.                             // Out of mem.  Cleanup and return
  797.                             free( pSvrAckPack );
  798.                             UnlockRange( minx, miny, maxx, maxy );
  799.                             UnlockPlayerData( pFromPlayer );
  800.                             return;       
  801.                         }
  802.  
  803.                         pSvrAckPack = pNewSvrAckPack;
  804.                         pChunk = (PlayerStatePacket*) ((BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket) ) );
  805.  
  806.                         // Make sure pChunk is still where its supposed to be
  807.                         assert( (BYTE*) pChunk == (BYTE*) ((BYTE*)pSvrAckPack + sizeof(ServerAckPacket) + pSvrAckPack->wPlayerStatePacketCount*sizeof(PlayerStatePacket)) );
  808.                     }
  809.  
  810.                     pChunk->dwID       = pCurPlayerData->dwID;
  811.                     pChunk->fX         = pCurPlayerData->fPosX;
  812.                     pChunk->fY         = pCurPlayerData->fPosY;
  813.                     pChunk->aCameraYaw = pCurPlayerData->aCameraYaw;
  814.                     pChunk++;
  815.                     pSvrAckPack->wPlayerStatePacketCount++;
  816.                 }
  817.                 pCurPlayerData = pCurPlayerData->pNextInCell;
  818.             }
  819.         }
  820.     }
  821.  
  822.     // Update the dwNumNearbyPlayers for this player
  823.     pFromPlayer->dwNumNearbyPlayers = pSvrAckPack->wPlayerStatePacketCount;
  824.  
  825.     // Unlock range of cells
  826.     UnlockRange( minx, miny, maxx, maxy );
  827.  
  828.     if( m_dwLogLevel > 2 )
  829.     {
  830.         ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );
  831.     }
  832.     else if( m_dwLogLevel == 2 )
  833.     {
  834.         FLOAT fTime = DXUtil_Timer( TIMER_GETAPPTIME );
  835.         if( fTime - pFromPlayer->fLastDisplayTime > 60.0f )
  836.         {
  837.             ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Position is (%0.2f,%0.2f)"), pFromPlayer->NetID, pFromPlayer->fPosX, pFromPlayer->fPosY );
  838.             pFromPlayer->fLastDisplayTime = fTime;
  839.         }
  840.     }
  841.  
  842.     // Unlock the playerdata
  843.     UnlockPlayerData( pFromPlayer );
  844.  
  845.     // Send acknowledgement back to client, including list of nearby players 
  846.     DWORD acksize = sizeof(ServerAckPacket) + (pSvrAckPack->wPlayerStatePacketCount * sizeof(PlayerStatePacket));
  847.  
  848.     // Pack the buffer with dummy data.
  849.     if(m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] > 0)
  850.     {
  851.         DWORD   dwBufferSize = acksize + m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex];
  852.         VOID*   pTempBuffer = 0;
  853.  
  854.         pTempBuffer = malloc(dwBufferSize);
  855.         if( NULL == pTempBuffer )
  856.         {
  857.             //Out of memory
  858.             DXTRACE_ERR_NOMSGBOX( TEXT("System out of Memory!"), E_OUTOFMEMORY );
  859.             free( pSvrAckPack );
  860.             return;
  861.         }
  862.  
  863.         FillMemory(pTempBuffer, dwBufferSize, 'Z');
  864.         memcpy(pTempBuffer, pSvrAckPack, acksize);
  865.  
  866.         SendPacket( dwFrom, pTempBuffer, dwBufferSize, FALSE, m_dwServerTimeout );
  867.     
  868.         free(pTempBuffer);
  869.     }   
  870.     else
  871.     {
  872.         SendPacket( dwFrom, pSvrAckPack, acksize, FALSE, m_dwServerTimeout );
  873.     }
  874.  
  875.     free( pSvrAckPack );
  876.  
  877. }
  878.  
  879.  
  880.  
  881.  
  882. //-----------------------------------------------------------------------------
  883. // Name: 
  884. // Desc: 
  885. //-----------------------------------------------------------------------------
  886. void CMazeServer::HandleClientVersionPacket( DWORD dwFrom, ClientVersionPacket* pClientVersionPack )
  887. {
  888.     // Grab playerdata for this client and lock it
  889.     PlayerData* pPlayerData = GetPlayerDataForID( dwFrom );
  890.     if( pPlayerData == NULL )
  891.         return;
  892.     LockPlayerData( pPlayerData );
  893.  
  894.     // Record the version number 
  895.     pPlayerData->dwVersion = pClientVersionPack->dwVersion;
  896.  
  897.     if( m_bLocalLoopback )
  898.         pPlayerData->bAllow = TRUE;
  899.     else
  900.         pPlayerData->bAllow = IsClientVersionSupported( pClientVersionPack->dwVersion );
  901.  
  902.     if( m_dwLogLevel > 0 )
  903.         ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Client version=%d (%s)"), pPlayerData->NetID, pPlayerData->dwVersion, pPlayerData->bAllow ? TEXT("Accepted") : TEXT("Rejected") );
  904.  
  905.     if( FALSE == pPlayerData->bAllow )
  906.     {
  907.         if( m_dwLogLevel > 0 )
  908.             ConsolePrintf( SLINE_LOG, TEXT("DPNID %0.8x: Rejecting client"), pPlayerData->NetID );
  909.  
  910.         m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
  911.         UnlockPlayerData( pPlayerData );
  912.         return;
  913.     }
  914.  
  915.     // Unlock the playerdata
  916.     UnlockPlayerData( pPlayerData );
  917.  
  918.     // Send acknowledgement to client that the client was either accepted or rejected
  919.     ServerAckVersionPacket packet( pPlayerData->bAllow, dwFrom );
  920.     SendPacket( dwFrom, &packet, sizeof(packet), TRUE, 0 );
  921. }
  922.  
  923.  
  924.  
  925.  
  926. //-----------------------------------------------------------------------------
  927. // Name: 
  928. // Desc: 
  929. //-----------------------------------------------------------------------------
  930. BOOL CMazeServer::IsClientVersionSupported( DWORD dwClientVersion )
  931. {
  932.     switch( dwClientVersion )
  933.     {
  934.         case 107: // only v107 is supported
  935.             return TRUE;
  936.         default:
  937.             return FALSE;
  938.     }
  939. }
  940.  
  941.  
  942.  
  943.  
  944. //-----------------------------------------------------------------------------
  945. // Name: 
  946. // Desc: 
  947. //-----------------------------------------------------------------------------
  948. void CMazeServer::HandleUnknownPacket( DWORD dwFrom, ClientPacket* pClientPack, DWORD size )
  949. {
  950.     if( m_dwLogLevel > 1 )
  951.         ConsolePrintf( SLINE_LOG, TEXT("ERROR! Unknown %d byte packet from player %0.8x"), size, dwFrom );
  952.  
  953.     m_pNet->RejectClient( dwFrom, DISCONNNECT_REASON_CLIENT_OUT_OF_DATE );
  954. }
  955.  
  956.  
  957.  
  958.  
  959. //-----------------------------------------------------------------------------
  960. // Name: 
  961. // Desc: 
  962. //-----------------------------------------------------------------------------
  963. DWORD   CMazeServer::IDHash( DWORD id )
  964. {
  965.     DWORD   hash = ((id) + (id>>8) + (id>>16) + (id>>24)) & (NUM_ID_HASH_BUCKETS-1);
  966.     return hash;
  967. }
  968.  
  969.  
  970.  
  971.  
  972. //-----------------------------------------------------------------------------
  973. // Name: 
  974. // Desc: 
  975. //-----------------------------------------------------------------------------
  976. void CMazeServer::RemovePlayerDataID( PlayerData* pPlayerData )
  977. {
  978.     // Hash the ID to a bucket number
  979.     DWORD   bucket = IDHash( pPlayerData->NetID );
  980.  
  981.     // Lock that hash bucket
  982.     const   DWORD   buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
  983.     m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
  984.  
  985.     // Loop though players in bucket until we find the right one
  986.     PlayerData* pPt = m_pstIDHashBucket[bucket];
  987.     PlayerData* pPrev = NULL;
  988.     while( pPt )
  989.     {
  990.         if( pPt == pPlayerData )
  991.             break;
  992.         pPrev = pPt;
  993.         pPt = pPt->pNextInIDHashBucket;
  994.     }
  995.  
  996.     if( pPt )
  997.     {
  998.         if( pPrev )
  999.             pPrev->pNextInIDHashBucket = pPt->pNextInIDHashBucket;
  1000.         else
  1001.             m_pstIDHashBucket[bucket] = pPt->pNextInIDHashBucket;
  1002.         pPt->pNextInIDHashBucket = NULL;
  1003.     }
  1004.  
  1005.     // Unlock the hash bucket
  1006.     m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
  1007. }
  1008.  
  1009.  
  1010.  
  1011.  
  1012. //-----------------------------------------------------------------------------
  1013. // Name: 
  1014. // Desc: 
  1015. //-----------------------------------------------------------------------------
  1016. void CMazeServer::SetPlayerDataForID( DWORD id, PlayerData* pPlayerData )
  1017. {
  1018.     // Make sure this player isn't added twice to the m_pstIDHashBucket[]
  1019.     // otherwise there will be a circular reference
  1020.     PlayerData* pSearch = GetPlayerDataForID( id );
  1021.     if( pSearch != NULL )
  1022.         return;
  1023.  
  1024.     // Hash the ID to a bucket number
  1025.     DWORD   bucket = IDHash( id );
  1026.  
  1027.     // Lock that hash bucket
  1028.     const   DWORD   buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
  1029.     m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
  1030.  
  1031.     // Add player onto hash bucket chain
  1032.     pPlayerData->pNextInIDHashBucket = m_pstIDHashBucket[bucket];
  1033.     m_pstIDHashBucket[bucket] = pPlayerData;
  1034.  
  1035.     // Store net id in player
  1036.     pPlayerData->NetID = id;
  1037.  
  1038.     // Unlock the hash bucket
  1039.     m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
  1040. }
  1041.  
  1042.  
  1043.  
  1044.  
  1045. //-----------------------------------------------------------------------------
  1046. // Name: 
  1047. // Desc: 
  1048. //-----------------------------------------------------------------------------
  1049. PlayerData* CMazeServer::GetPlayerDataForID( DWORD id )
  1050. {
  1051.     // Hash the ID to a bucket number
  1052.     DWORD   bucket = IDHash( id );
  1053.  
  1054.     // Lock that hash bucket
  1055.     const   DWORD   buckets_per_lock = NUM_ID_HASH_BUCKETS / NUM_ID_HASH_BUCKET_LOCKS;
  1056.     m_IDHashBucketLocks[bucket/buckets_per_lock].Enter();
  1057.  
  1058.     // Loop though players in bucket until we find the right one
  1059.     PlayerData* pPlayerData = m_pstIDHashBucket[bucket];
  1060.     while ( pPlayerData )
  1061.     {
  1062.         if( pPlayerData->NetID == id )
  1063.             break;
  1064.         pPlayerData = pPlayerData->pNextInIDHashBucket;
  1065.     }
  1066.  
  1067.     // Unlock the hash bucket
  1068.     m_IDHashBucketLocks[bucket/buckets_per_lock].Leave();
  1069.  
  1070.     // Return the player we found (will be NULL if we couldn't find it)
  1071.     return pPlayerData;
  1072. }
  1073.  
  1074.  
  1075.  
  1076.  
  1077. //-----------------------------------------------------------------------------
  1078. // Name: 
  1079. // Desc: calls DisplayConnectionInfo for each connection in a round-robin manner
  1080. //-----------------------------------------------------------------------------
  1081. void CMazeServer::DisplayNextConnectionInfo()
  1082. {
  1083.     if( m_pNet )
  1084.     {
  1085.         // Find the player that was displayed the longest time ago, and display it.
  1086.         FLOAT fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
  1087.         PlayerData* pOldestPlayerData = NULL;
  1088.         FLOAT fOldestTime = 0.0f;
  1089.  
  1090.         m_PlayerDataListLock.Enter();
  1091.  
  1092.         PlayerData* pPlayerData = m_pFirstActivePlayerData;
  1093.         while ( pPlayerData )
  1094.         {
  1095.             if( fCurTime - pPlayerData->fLastCITime > fOldestTime )
  1096.             {
  1097.                 fOldestTime  = fCurTime - pPlayerData->fLastCITime;
  1098.                 pOldestPlayerData = pPlayerData;
  1099.             }
  1100.  
  1101.             pPlayerData = pPlayerData->pNext;
  1102.         }
  1103.  
  1104.         // Display the player with the oldest CI field, and update its CI field.
  1105.         if( pOldestPlayerData )
  1106.         {
  1107.             ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for next player") );
  1108.             DisplayConnectionInfo( pOldestPlayerData->NetID );
  1109.             pOldestPlayerData->fLastCITime = fCurTime;
  1110.         }
  1111.         else
  1112.         {
  1113.             ConsolePrintf( SLINE_LOG, TEXT("No players found") );
  1114.         }
  1115.  
  1116.         m_PlayerDataListLock.Leave();
  1117.     }
  1118. }
  1119.  
  1120.  
  1121.  
  1122.  
  1123. //-----------------------------------------------------------------------------
  1124. // Name: 
  1125. // Desc: 
  1126. //-----------------------------------------------------------------------------
  1127. void CMazeServer::PrintStats()
  1128. {
  1129.     ConsolePrintf( SLINE_LOG, TEXT("Thread count: Active=%d Avg=%.2f Max=%d"), 
  1130.                                     m_wActiveThreadCount, m_fAvgThreadCount, m_wMaxThreadCount );
  1131.     ConsolePrintf( SLINE_LOG, TEXT("Thread Time: Avg=%.4f Max=%.4f(s)"),
  1132.                                     m_fAvgThreadTime, m_fMaxThreadTime );
  1133.     ConsolePrintf( SLINE_LOG, TEXT("Players online (not including server player): %d"), m_dwPlayerCount );
  1134.     ConsolePrintf( SLINE_LOG, TEXT("Peak player count: %d"), m_dwPeakPlayerCount );
  1135. }
  1136.  
  1137.  
  1138.  
  1139.  
  1140. //-----------------------------------------------------------------------------
  1141. // Name: 
  1142. // Desc: 
  1143. //-----------------------------------------------------------------------------
  1144. void CMazeServer::DisplayConnectionInfo( DWORD dwID )
  1145. {
  1146.     TCHAR strInfo[5000];
  1147.     TCHAR* strEndOfLine;
  1148.     TCHAR* strStartOfLine;
  1149.  
  1150.     // Query the IOutboudNet for info about the connection to this user
  1151.     m_pNet->GetConnectionInfo( dwID, strInfo );
  1152.  
  1153.     ConsolePrintf( SLINE_LOG, TEXT("Displaying connection info for %0.8x"), dwID );
  1154.     ConsolePrintf( SLINE_LOG, TEXT("(Key: G=Guaranteed NG=Non-Guaranteed B=Bytes P=Packets)") );
  1155.  
  1156.     // Display each line seperately
  1157.     strStartOfLine = strInfo;
  1158.     while( TRUE )
  1159.     {
  1160.         strEndOfLine = _tcschr( strStartOfLine, '\n' );
  1161.         if( strEndOfLine == NULL )
  1162.             break;
  1163.  
  1164.         *strEndOfLine = 0;
  1165.         ConsolePrintf( SLINE_LOG, strStartOfLine );
  1166.         strStartOfLine = strEndOfLine + 1;
  1167.     }
  1168. }
  1169.  
  1170.  
  1171.  
  1172.  
  1173. //-----------------------------------------------------------------------------
  1174. // Name: 
  1175. // Desc: 
  1176. //-----------------------------------------------------------------------------
  1177. HRESULT CMazeServer::SendPacket( DWORD to, void* pData, 
  1178.                                  DWORD size, BOOL reliable, DWORD dwTimeout )
  1179. {
  1180.     // Chance of forcing any packet to be delivered reliably
  1181.     if( m_Rand.Get( 100 ) < m_dwServerReliableRate )
  1182.         reliable = TRUE;
  1183.  
  1184.     return m_pNet->SendPacket( to, pData, size, reliable, dwTimeout );
  1185. }
  1186.  
  1187.  
  1188.  
  1189.  
  1190. //-----------------------------------------------------------------------------
  1191. // Name: 
  1192. // Desc: 
  1193. //-----------------------------------------------------------------------------
  1194. void CMazeServer::SendConfigPacketToAll( ServerConfigPacket* pPacket )
  1195. {
  1196.     // If we're up and running, then send this new information to all clients
  1197.     if( m_pNet )
  1198.     {
  1199.         //Use the AllPlayers ID
  1200.         SendPacket( DPNID_ALL_PLAYERS_GROUP, pPacket, sizeof(ServerConfigPacket), TRUE, 0 );
  1201.     }
  1202. }
  1203.  
  1204.  
  1205.  
  1206.  
  1207. //-----------------------------------------------------------------------------
  1208. // Name: 
  1209. // Desc: 
  1210. //-----------------------------------------------------------------------------
  1211. void CMazeServer::SetClientReliableRate( DWORD percent )
  1212. {
  1213.     // Update client config, and build packet containing that data
  1214.     m_ClientNetConfigLock.Enter();
  1215.     m_ClientNetConfig.ubReliableRate = BYTE(percent);
  1216.     ServerConfigPacket packet( m_ClientNetConfig );
  1217.     m_ClientNetConfigLock.Leave();
  1218.  
  1219.     SendConfigPacketToAll( &packet );
  1220. }
  1221.  
  1222.  
  1223.  
  1224.  
  1225. //-----------------------------------------------------------------------------
  1226. // Name: 
  1227. // Desc: 
  1228. //-----------------------------------------------------------------------------
  1229. void CMazeServer::SetClientUpdateRate( DWORD rate )
  1230. {
  1231.     // Update client config, and build packet containing that data
  1232.     m_ClientNetConfigLock.Enter();
  1233.     m_ClientNetConfig.wUpdateRate = WORD(rate);
  1234.     ServerConfigPacket  packet( m_ClientNetConfig );
  1235.     m_ClientNetConfigLock.Leave();
  1236.  
  1237.     SendConfigPacketToAll( &packet );
  1238. }
  1239.  
  1240.  
  1241.  
  1242.  
  1243. //-----------------------------------------------------------------------------
  1244. // Name: 
  1245. // Desc: 
  1246. //-----------------------------------------------------------------------------
  1247. void CMazeServer::SetClientTimeout( DWORD timeout )
  1248. {
  1249.     // Update client config, and build packet containing that data
  1250.     m_ClientNetConfigLock.Enter();
  1251.     m_ClientNetConfig.wTimeout = WORD(timeout);
  1252.     ServerConfigPacket  packet( m_ClientNetConfig );
  1253.     m_ClientNetConfigLock.Leave();
  1254.  
  1255.     SendConfigPacketToAll( &packet );
  1256. }
  1257.  
  1258.  
  1259.  
  1260.  
  1261. //-----------------------------------------------------------------------------
  1262. // Name: 
  1263. // Desc: 
  1264. //-----------------------------------------------------------------------------
  1265. void CMazeServer::SetClientPackSize( DWORD size )
  1266. {
  1267.     // Update client config, and build packet containing that data
  1268.     m_ClientNetConfigLock.Enter();
  1269.     
  1270.     m_ClientNetConfig.ubClientPackIndex++; //Increase index and verify location in array.
  1271.     if(m_ClientNetConfig.ubClientPackIndex >= PACK_ARRAY_SIZE)   
  1272.         m_ClientNetConfig.ubClientPackIndex = 0;
  1273.  
  1274.     m_ClientNetConfig.wClientPackSizeArray[m_ClientNetConfig.ubClientPackIndex] = WORD(size);
  1275.     ServerConfigPacket packet( m_ClientNetConfig );
  1276.     m_ClientNetConfigLock.Leave();
  1277.  
  1278.     SendConfigPacketToAll( &packet );
  1279. }
  1280.  
  1281.  
  1282.  
  1283.  
  1284. //-----------------------------------------------------------------------------
  1285. // Name: 
  1286. // Desc: 
  1287. //-----------------------------------------------------------------------------
  1288. void CMazeServer::SetServerPackSize( DWORD size )
  1289. {
  1290.     // Update client config, and build packet containing that data
  1291.     m_ClientNetConfigLock.Enter();
  1292.     
  1293.     m_ClientNetConfig.ubServerPackIndex++; //Increase index and verify location in array.
  1294.     if(m_ClientNetConfig.ubServerPackIndex >= PACK_ARRAY_SIZE)   
  1295.         m_ClientNetConfig.ubServerPackIndex = 0;
  1296.  
  1297.     m_ClientNetConfig.wServerPackSizeArray[m_ClientNetConfig.ubServerPackIndex] = WORD(size);
  1298.     ServerConfigPacket packet( m_ClientNetConfig );
  1299.     m_ClientNetConfigLock.Leave();
  1300.  
  1301.     SendConfigPacketToAll( &packet );
  1302. }
  1303.  
  1304.  
  1305. //-----------------------------------------------------------------------------
  1306. // Name: 
  1307. // Desc: 
  1308. //-----------------------------------------------------------------------------
  1309. void CMazeServer::SetClientThreadWait( DWORD dwThreadWait )
  1310. {
  1311.     // Update client config, and build packet containing that data
  1312.     m_ClientNetConfigLock.Enter();
  1313.     
  1314.     m_ClientNetConfig.dwThreadWait = dwThreadWait;
  1315.     ServerConfigPacket packet( m_ClientNetConfig );
  1316.     m_ClientNetConfigLock.Leave();
  1317.  
  1318.     SendConfigPacketToAll( &packet );
  1319. }
  1320.